// 使用class语法

class Vue {

}

/*
类的属性和方法有三类：实例属性方法，原型属性方法，静态属性方法
1、实例属性方法：函数里使用this定义的，class的constructor方法里使用this定义。
2、原型属性方法：函数使用prototype对象定义，class里和constructor方法同级定义
3、静态属性方法：函数直接在自身最外层定义，class里使用static关键字定义。
*/
class Compile {
    // ES6规定，Class内部只有静态方法，无静态属性。以下两种写法都是错的
    // prop: 2
    // static prop : 2

    constructor(el, vm) {
        this.vm = vm;
        vm.$el = document.querySelector(el);
        const fragment = document.createDocumentFragment();
        let child = null;
        while (child = vm.$el.firstChild) { // 执行child = vm.$el.firstChild赋值语句，该语句返回值是vm.$el.firstChild，为true
            fragment.append(child); // 会从vm.$el里将child移走，并添加到fragment对象里。append一个已经存在于文档中的dom结构，相当于将它从原位置移动到新位置。这样vm.$el每次就会少一个子节点。
        }
        this.replace(fragment);
        vm.$el.append(fragment); // 模板替换完毕，将fragment插入到已经空了的vm.$el中。至此，模板编译完成。

    }


    // 类内部所有定义的方法，都是不可枚举的，与ES5不一样
    // 原型方法：定义在类的prototype属性上：Compile.prototype.replace
    replace(fragment) {
        const pattern = /\{\{(.*)\}\}/;
        let arr = [];
        Array.from(fragment.childNodes).forEach(node => {
            let text = node.textContent;
            if (node.nodeType === 3 && pattern.test(text)) {
                const key = RegExp.$1.trim();
                node.textContent = text.replace(pattern, vm[key]); // 将替换相应文本节点值的代码复用
                arr.push({ // 要让arr在Observe里可调用
                    dataKey: key,
                    fun: (newVal) => {
                        node.textContent = text.replace(pattern, newVal);
                    }
                })
            }
            if (node.childNodes && node.childNodes.length) {
                this.replace(node);
            }
        });
        new Replace(this.vm, arr);
    }

    textNodeReplaceValue(textNode, ) {

    }
}

class Replace {
    constructor(vm, arr){
        this.vm = vm;
        this.arr = arr;
    }

    updateAll() {
        this.arr.forEach(function(keyObj) {
            keyObj.fun(this.vm[keyObj.dataKey]);
        });
    }
}

function Test() {
}
// 最重要的一步就是将模板替换代码和监听器联系起来
class Observer{
    constructor(data) {
        for (const key in data) {
            let val = data[key];
            Object.defineProperty(data, key, {
                enumerable: true,
                get() { // 取值
                    return val;
                },
                set(newVal) { // 赋值
                    if (newVal === val) {
                        return;
                    }
                    val = newVal;
                    // 调用相应文本节点替换方法
                }
            });
        }
    }
}